package main

import (
	"fmt"
	"reflect"
)

// Student 学生信息
type Student struct {
	Name string `json:"name"`
	Age  int8   `json:"age"`
}

// Print 方法如果不能导出，那么反射则获取不到
func (this Student) Print() {
	fmt.Println(this)
}

// GetSum 求和
func (this Student) GetSum(n1, n2 int) int {
	return n1 + n2
}

// ReflectForTest 遍历结构体字段，标签
func ReflectForTest(a interface{}) {
	rType := reflect.TypeOf(a)
	rVal := reflect.ValueOf(a)

	fieldNum := rType.NumField()

	for i := 0; i < fieldNum; i++ {
		fieldName := rType.Field(i).Name
		fieldValue := rVal.Field(i)
		fieldTag := rType.Field(i).Tag.Get("json")

		fmt.Println(fieldName, fieldValue, fieldTag)
	}
	// Name jack name
	// Age 18 age
}

// marshal 序列化
func marshal(a interface{}) string {
	rType := reflect.TypeOf(a)
	rVal := reflect.ValueOf(a)

	fieldNum := rType.NumField()
	res := "{"

	for i := 0; i < fieldNum; i++ {
		fieldName := rType.Field(i).Name
		fieldValue := rVal.Field(i)
		fieldTag := rType.Field(i).Tag.Get("json")

		if i == fieldNum-1 {
			if fieldTag != "" {
				res += fmt.Sprintf("%v=%v", fieldTag, fieldValue)
			} else {
				res += fmt.Sprintf("%v=%v", fieldName, fieldValue)
			}
		} else {
			if fieldTag != "" {
				res += fmt.Sprintf("%v=%v, ", fieldTag, fieldValue)
			} else {
				res += fmt.Sprintf("%v=%v, ", fieldName, fieldValue)
			}
		}
	}
	res += "}"
	return res
}

// updateVal 修改结构体的值
func updateVal(a interface{}) {
	rVal := reflect.ValueOf(a).Elem()

	fieldNum := rVal.NumField()
	for i := 0; i < fieldNum; i++ {
		val := rVal.Field(i)
		if val.Kind() == reflect.Int8 {
			val.SetInt(127)
		} else if val.Kind() == reflect.String {
			val.SetString("marry")
		}

	}
}

// callMethod 调用方法 注意：方法调用索引是根据 方法ASCII排序的
func callMethod(a interface{}) {
	rVal := reflect.ValueOf(a)

	methodNum := rVal.NumMethod()
	fmt.Println("method num is ", methodNum)
	rVal.Method(1).Call(nil) // call second method

	var param []reflect.Value
	param = append(param, reflect.ValueOf(10))
	param = append(param, reflect.ValueOf(20))
	res := rVal.Method(0).Call(param) // call first method GetSum() int
	fmt.Println(res[0].Int())         // 30
}
func main() {
	stu := Student{
		Name: "jack",
		Age:  18,
	}

	//ReflectForTest(stu)
	// Name jack name
	// Age 18 age
	//res := marshal(stu)
	//fmt.Println(res) // {name=jack, age=18}

	//updateVal(&stu)
	//
	//fmt.Println(stu) // {marry 127}

	callMethod(stu)
}
